Skip to content

Fix phpstan/phpstan#13453: Templated return type error message is self-contradictory#5352

Open
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-epcrhal
Open

Fix phpstan/phpstan#13453: Templated return type error message is self-contradictory#5352
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-epcrhal

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When two different template types have the same name and bound but belong to different scopes (e.g., a function template T of ResultA and an interface template T of ResultA), error messages like "should return T of ResultA but returns T of ResultA" were self-contradictory and confusing to users. The fix escalates the verbosity level to precise when both types produce identical descriptions, adding scope information to disambiguate them.

Changes

  • Modified VerbosityLevel::getRecommendedLevelByType() in src/Type/VerbosityLevel.php to detect when accepting and accepted types have identical descriptions at the chosen level, and escalate to precise verbosity in that case
  • Added regression test in tests/PHPStan/Rules/Functions/data/bug-13453.php and corresponding test method in tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php

Root cause

VerbosityLevel::getRecommendedLevelByType() chose verbosity based on type complexity (constant values, callables, accessory types, etc.) but never considered whether the two types being compared would produce identical string descriptions. Template types from different scopes with the same name and bound are semantically different but described identically at typeOnly and value verbosity levels. Only at precise level does the scope information (e.g., "function run(), argument" vs "class I, parameter") get included.

Test

The regression test reproduces the exact scenario from the issue: a function with @template T of ResultA returning a value whose type is T of ResultA from an interface template. The test verifies the error message now includes scope disambiguation.

Fixes phpstan/phpstan#13453

…iptions in error messages

- When two different template types produce the same description at the chosen verbosity level, escalate to precise verbosity to include scope information
- This fixes self-contradictory messages like "should return T of ResultA but returns T of ResultA" by showing "T of ResultA (function run(), argument) but returns T of ResultA (class I, parameter)"
- New regression test in tests/PHPStan/Rules/Functions/data/bug-13453.php
Copy link
Copy Markdown
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made two changes, but only one test ; could you test the other change too ?

…late types

Cover the second code path in VerbosityLevel::getRecommendedLevelByType()
where containsInvariantTemplateType is true. The test uses a generic
Container<T> (invariant template) wrapping template types from different
scopes that would otherwise produce identical descriptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

Done. I added a test (testBug13453Invariant) that covers the second code path in VerbosityLevel::getRecommendedLevelByType() — the branch where $containsInvariantTemplateType is true. The test uses a generic Container<T> (which has an invariant template by default) wrapping template types from different scopes (function run() vs class I), verifying that the descriptions are disambiguated with scope information when they would otherwise be identical.

@VincentLanglet VincentLanglet self-assigned this Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants